package com.ruoyi.equip.ws;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.equip.domain.dto.WsDto;
import com.ruoyi.equip.domain.vo.RealDataVo;
import com.ruoyi.equip.domain.vo.WsVo;
import com.ruoyi.equip.service.IDeviceInfoService;
import com.ruoyi.equip.util.HeartCacheUtils;
import com.ruoyi.equip.util.ProductCacheUtils;
import com.ruoyi.equip.vert.service.impl.DataTransfer;
import com.ruoyi.td.entity.DevicePropertyCache;
import com.ruoyi.td.service.IDeviceInfoData;
import org.apache.commons.math3.stat.inference.MannWhitneyUTest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@ServerEndpoint("/ws/{sid}")
@Component
public class WebSocketServer {

    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);

    private static int onlineCount = 0;

    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();

    private static ConcurrentHashMap<String, WebSocketServer> sessionMap = new ConcurrentHashMap<>();

    private Session session;

    private String sid = "";
    // 标志位，用于跟踪会话的关闭状态
    private boolean closed = false;
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        this.session = session;
        this.sid = sid;

        if (sessionMap.containsKey(sid)) {
            sessionMap.get(sid).session = session;  // 恢复会话
        } else {
            sessionMap.put(sid, this);
            addOnlineCount(); // 在线数加1
            webSocketSet.add(this); // 加入set中

        }
    }

    @OnClose
    public void onClose() {
        if (!closed) {
            if (sessionMap.containsKey(this.sid)){
                closed = true; // 设置标志位，防止重复执行
                webSocketSet.remove(this); // 从set中删除
                sessionMap.remove(this.sid); // 从session map中删除
                subOnlineCount(); // 在线数减1
            }
        }

    }

    @OnMessage
    public void onMessage(String message, Session session) {
        WsDto wsDto = JSONObject.parseObject(message, WsDto.class);
            try {
                switch (wsDto.getType()) {
                    case "readerList":
                        List<String> deviceIds = wsDto.getPayload().getDeviceIds();
                        Map<String, Boolean> online = getOnline(deviceIds);
                        WsVo wsVo1 = new WsVo();
                        wsVo1.setType("readerList");
                        wsVo1.setPayload(new WsVo.PayloadVo(online));
                        sendMessage(JSONObject.toJSONString(wsVo1));
                        break;
                    case "tagList":
                        List<String> tagDeviceIds = wsDto.getPayload().getDeviceIds();
                        Map<String, Boolean> tagOnline = getOnline(tagDeviceIds);
                        WsVo wsVo2 = new WsVo();
                        wsVo2.setType("tagList");
                        wsVo2.setPayload(new WsVo.PayloadVo(tagOnline));
                        sendMessage(JSONObject.toJSONString(wsVo2));
                        break;
                    case "tagProperty":
                        IDeviceInfoData deviceInfoData = SpringUtils.getBean(IDeviceInfoData.class);
                        String tagId = wsDto.getPayload().getTagId();
                        Map<String, DevicePropertyCache> properties = deviceInfoData.getProperties(tagId);
                        WsVo wsVo3 = new WsVo();
                        wsVo3.setType("tagProperty");
                        wsVo3.setPayload(new WsVo.PayloadVo(properties));
                        sendMessage(JSONObject.toJSONString(wsVo3));
                        break;
                    case "realData":
                        IDeviceInfoData realDeviceInfoData = SpringUtils.getBean(IDeviceInfoData.class);
                        List<String> tagIds = wsDto.getPayload().getTagIds();
                        WsVo wsVo4 = new WsVo();
                        wsVo4.setType("realData");
                        Map<String, RealDataVo> datas = new HashMap<>();
                        tagIds.forEach(tag -> {
                            RealDataVo realDataVo = new RealDataVo(HeartCacheUtils.isOnline(tag), DataTransfer.realData.get(tag));
                            datas.put(tag, realDataVo);
                        });
                        wsVo4.setPayload(new WsVo.PayloadVo(datas));
                        sendMessage(JSONObject.toJSONString(wsVo4));
                        break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }



    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
        return webSocketSet;
    }

    public Map<String, Boolean> getOnline(List<String> deviceIds) {
        HashMap<String, Boolean> onlineMap = new HashMap<>();
        deviceIds.forEach(deviceId -> {
            onlineMap.put(deviceId, HeartCacheUtils.isOnline(deviceId));
        });
        return onlineMap;
    }
}
